using namespace std;
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <cassert>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstdlib>
#include <sys/wait.h>
#include <ctime>
#define PROCESS_NUM 5
typedef void(*func)();


class SubEp
{
public:
    SubEp(pid_t Subid,int WriteFd)
    :subId_(Subid)
    ,WriteFd_(WriteFd)
    {
        char Buffer[1024];
        snprintf(Buffer,sizeof(Buffer),"process-%d[pid(%d)-fd(%d)]",num++,Subid,WriteFd);
        name_ = Buffer;
    }
public:
    static int num;
    string name_;
    pid_t subId_;
    int WriteFd_;
};
int SubEp::num=0;
void DownTask()
{
    cout<<getpid()<<": 正在下载"<<endl;
    sleep(1);
}
void Print()
{
    cout<<getpid()<<": 正在打印"<<endl;
    sleep(1);
}
void Moyu()
{
    cout<<getpid()<<": 正在摸鱼"<<endl;
    sleep(1);
}
void IOTask()
{
    cout<<getpid()<<": 正在进行IO"<<endl;
    sleep(1);
}
void LoadTask(vector<func>& funcs)
{
    funcs.push_back(DownTask);
    funcs.push_back(IOTask);
    funcs.push_back(Print);
    funcs.push_back(Moyu);
}


void SendTask(SubEp& process,int TaskNum)
{
    cout<<"send task num: "<<TaskNum<<"send to -> " <<process.name_<<endl;
    ssize_t n = write(process.WriteFd_,&TaskNum,sizeof(TaskNum));
    assert(n == sizeof(TaskNum));
    (void)n;
}

int recvTask(int ReadFd)
{
    int code = -1;
    ssize_t s=read(ReadFd,&code,sizeof(ReadFd));
    assert(s == sizeof(ReadFd));
    if(s==4) return code;
    else if(s <=0 )return -1;
    else return 0;
}
void creatSubProcess(vector<SubEp>& subs,vector<func>& funcs)
{
    vector<int> deleteFd;
    for(int i=0; i < PROCESS_NUM; ++i)
    {
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        (void)n;
        pid_t id = fork();
        if(id == 0)
        {
            for(int i=0;i<deleteFd.size();++i)
            close(deleteFd[i]);
            //子进程,进行处理任务关闭写
            close(fds[1]);
            while(1)
            {
                int CommandCode = recvTask(fds[0]);
                if(CommandCode >=0 && CommandCode < funcs.size())funcs[CommandCode]();
                else cout<<"sub recv code error！"<<endl;
            }
            exit(0);
        }
        //关闭读
        close(fds[0]);
        SubEp sub(id,fds[1]);
        subs.push_back(sub);
        deleteFd.push_back(fds[1]);
    }
}

void waitProcess(vector<SubEp>& Process)
{
    int processnum=Process.size();
    for(int i=0;i<processnum;++i)
    {
        waitpid(Process[i].subId_,nullptr,0);
        cout<<"wait sub process success ...:"<<Process[i].subId_<<endl;
    }
}
void MakeSeek()
{
    srand(time(nullptr) ^ 0x1734 ^ rand()%1234);
}

void loadBlanceContrl(vector<SubEp> &subs,const vector<func> &funcMap, int count)
{
    int processnum = subs.size();
    int tasknum = funcMap.size();
    bool forever = (count == 0 ? true : false);

    while (true)
    {
        // 1. 选择一个子进程 --> std::vector<subEp> -> index - 随机数
        int subIdx = rand() % processnum;
        // 2. 选择一个任务 --> std::vector<func_t> -> index
        int taskIdx = rand() % tasknum;
        // 3. 任务发送给选择的进程
        SendTask(subs[subIdx], taskIdx);
        sleep(1);
        if(!forever)
        {
            count--;
            if(count == 0) break;   
        }
    }
    // write quit -> read 0
    for(int i = 0; i < processnum; i++) close(subs[i].WriteFd_); // waitpid();
}
int main()
{
    MakeSeek();
    vector<func> funcs;
    LoadTask(funcs);
    vector<SubEp> subs;
    //1.建立子进程并建立和子进程之间通信的管道,有Bug,但是不影响我们后面的编写
    //[子进程id,wfd]   
    creatSubProcess(subs,funcs);
    //2.走到这里只能是父进程，控制子进程
    loadBlanceContrl(subs,funcs,10);

    //3.回收子进程信息
    waitProcess(subs);
    return 0;
}
